home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Utilities / FocusLib.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  12.0 KB  |  486 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FocusLib.cpp
  3.  
  4.     Contains:    Library routines for focusing (setting up for drawing into a facet)
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13. #ifndef _ALTPOINT_
  14. #include <AltPoint.h>
  15. #endif
  16.  
  17. #ifndef _ALTPOLY_
  18. #include <AltPoly.h>
  19. #endif
  20.  
  21. #ifndef _ODDEBUG_
  22. #include "ODDebug.h"
  23. #endif
  24.  
  25. #ifndef SOM_ODFrame_xh
  26. #include <Frame.xh>
  27. #endif
  28.  
  29. #ifndef SOM_ODFacet_xh
  30. #include <Facet.xh>
  31. #endif
  32.  
  33. #ifndef _TEMPOBJ_
  34. #include <TempObj.h>
  35. #endif
  36.  
  37. #ifndef _PLFMDEF_
  38. #include <PlfmDef.h>
  39. #endif
  40.  
  41. #ifndef SOM_ODShape_xh
  42. #include <Shape.xh>
  43. #endif
  44.  
  45. #ifndef SOM_Module_OpenDoc_Polygon_defined
  46. #include <Polygon.xh>
  47. #endif
  48.  
  49. #ifndef SOM_ODTransform_xh
  50. #include <Trnsform.xh>
  51. #endif
  52.  
  53. #ifndef SOM_ODCanvas_xh
  54. #include <Canvas.xh>
  55. #endif
  56.  
  57. #ifndef SOM_ODWindow_xh
  58. #include <Window.xh>
  59. #endif
  60.  
  61. #ifndef SOM_ODFacet_xh
  62. #include <Facet.xh>
  63. #endif
  64.  
  65. #ifndef _FOCUSLIB_
  66. #include "FocusLib.h"
  67. #endif
  68.  
  69. #ifndef __PRINTING__
  70. #include <Printing.h>
  71. #endif
  72.  
  73. #ifndef _ODUTILS_
  74. #include "ODUtils.h"
  75. #endif
  76.  
  77. #ifndef _ODMEMORY_
  78. #include "ODMemory.h"
  79. #endif
  80.  
  81. #include <string.h>
  82. #include <stdio.h>
  83.  
  84. #ifndef topLeft
  85. #define topLeft(r)        (((Point *) &(r))[0])
  86. #endif
  87.  
  88. #define bDevLaser            3        // copied from "PrPrivate.a"
  89.  
  90. #define kPostScriptHandle    192        // Picture comment ID
  91.  
  92.  
  93. #define ALWAYS_PS_CLIP        0        // Set to 1 to always use PS clipping even for rects
  94.                                     // This aids in debugging the clipping code.
  95.  
  96.  
  97. //------------------------------------------------------------------------------
  98. // GetCanvasGeometryMode
  99. //------------------------------------------------------------------------------
  100.  
  101. ODGeometryMode
  102. GetCanvasGeometryMode( Environment *ev, ODCanvas *canvas )
  103. {
  104.     ODGeometryMode mode = kODLoseGeometry;
  105.     if( !canvas->IsDynamic(ev) ) {
  106.         if( canvas->HasPlatformPrintJob(ev,kODQuickDrawGX) )
  107.             mode = kODPreserveGeometry;
  108.         else if( canvas->HasPlatformPrintJob(ev,kODQuickDraw) ) {
  109.             THPrint job = (THPrint) canvas->GetPlatformPrintJob(ev,kODQuickDraw);
  110.             if( ((**job).prStl.wDev >>8) == bDevLaser )
  111.                 mode = kODPreserveGeometry;
  112.         }
  113.         // ????? Should I also treat onscreen canvases as geometric, if GX is installed??
  114.     }
  115.     return mode;
  116. }
  117.  
  118.  
  119. //------------------------------------------------------------------------------
  120. // Begin / EndPostScriptClip
  121. //------------------------------------------------------------------------------
  122.  
  123. static void
  124. NoOpDraw( )
  125. {
  126.     // Draw something that's guaranteed not to appear anywhere.
  127.     // Needed to sync up QD-emitted PS code with SendPS-emitted code.
  128.     Rect bbox = (**ODQDGlobals.thePort->clipRgn).rgnBBox;
  129.     Point pt;
  130.     pt.h = bbox.left;
  131.     if( pt.h==-32767 )
  132.         pt.h = bbox.right+1;
  133.     pt.v = bbox.top;
  134.     if( pt.v==-32767 )
  135.         pt.v = bbox.bottom+1;
  136.     MoveTo(pt.h-1,pt.v-1);
  137.     Line(0,0);
  138. }
  139.  
  140.  
  141. static void
  142. SendPS( const char str[] )
  143. {
  144.     OSErr err;
  145.     ODULong len = strlen(str) +1;
  146.     ODHandle h = TempNewHandle(len,&err);
  147.     if( !h )
  148.         h = NewHandle(len);                                // In emergency use app heap
  149.         
  150.     if( h ) {
  151.         ODBlockMove(str,*h,len-1);
  152.         ((char*)*h)[len-1] = 13;                        // Append Return char
  153.         PicComment(kPostScriptHandle, len, h);
  154.         DisposeHandle(h);
  155.     } else
  156.         WARN("Couldn't allocate %ld bytes for PicComment",len);
  157. }
  158.  
  159.  
  160. void
  161. ODBeginPostScriptClip( Environment* ev, ODShape *shape )
  162. {
  163.     /*    Since the LaserWriter driver does not understand regions, in order to clip to
  164.         a nonrectangular shape we must convert it to a polygon, then emit PostScript code
  165.         to create a path in the shape of that polygon and clip to it. This involves
  166.         some nonstandard use of the PostScript picture-comments in that we deliberately
  167.         do _not_ use PostScriptBegin and PostScriptEnd comments. The purpose of these is
  168.         to save and restore the state of the printer, and that's exactly what we don't
  169.         want to do here -- we need the new clipping path to be applied to future QD
  170.         drawing. */
  171.     
  172.     SendPS("%%%% ODBeginPostScriptClip");
  173.     
  174.     // First clip to the region (LW driver will just use the bounding box.)
  175.     RgnHandle rgn = shape->GetQDRegion(ev);
  176.     SetClip(rgn);
  177.     NoOpDraw();
  178.  
  179.     if( !shape->IsRectangular(ev) || ALWAYS_PS_CLIP ) {
  180.         // Now emit the polygon as a PostScript path and clip to it:
  181.         ODTempPolygon poly; 
  182.         shape->CopyPolygon(ev, &poly);
  183.         
  184.         SendPS("gsave newpath");                            // Save graphics state first
  185.         
  186.         float xoff = ODQDGlobals.thePort->portRect.left;    // Must emit page coords
  187.         float yoff = ODQDGlobals.thePort->portRect.top;
  188.         
  189.         char buf[128];
  190.         ODContour *cont = poly.FirstContour();
  191.         for( long n=poly.GetNContours(); n>0; n-- ) {
  192.             const ODPoint *v = cont->vertex;
  193.             long m = cont->nVertices;
  194.             if( m>2 ) {
  195.                 const char *op = "moveto";
  196.                 while( m-- >0 ) {
  197.                     sprintf(buf,"%.2f %.2f %s", v->x/65536.0-xoff, v->y/65536.0-yoff, op);
  198.                     SendPS(buf);
  199.                     op = "lineto";
  200.                     v++;
  201.                 }
  202.             }
  203.             SendPS("closepath");
  204.             cont = cont->NextContour();
  205.         }
  206.         
  207.         SendPS("clip gsave");                // Driver expects copy of state pushed on stack
  208.         
  209.     } else {
  210.         // Regular rectangular clipping. Just need to emit two gsaves
  211.         // to balance the two grestores that ODEndPostScriptClip will emit:
  212.         SendPS("gsave gsave");
  213.     }
  214. }
  215.  
  216.  
  217. void
  218. ODEndPostScriptClip(  )
  219. {
  220.     NoOpDraw();
  221.     SendPS("currentpoint grestore grestore moveto");            // Preserve current point
  222.     SendPS("%%%% ODEndPostScriptClip");
  223. }
  224.  
  225.  
  226. //------------------------------------------------------------------------------
  227. // FocusState::BeginFocus
  228. //------------------------------------------------------------------------------
  229.  
  230. ODBoolean
  231. FocusState::BeginFocus( Environment* ev, ODFacet *facet, ODBoolean toContent,
  232.                             ODBoolean toWindow, ODShape *clipTo )
  233. {
  234.     GrafPtr port;
  235.     ODPoint offset;
  236.     Point origin;
  237.     
  238.     fPort = kODNULL;
  239.     fOrigin.h = fOrigin.v = 0;
  240.     fClip = kODNULL;
  241.     fPrintingPostScript = kODFalse;
  242.     
  243.     ODBoolean printing = kODFalse;
  244.     if( ! facet->GetCanvas(ev)->IsDynamic(ev) ) {
  245.         if( facet->GetCanvas(ev)->HasPlatformPrintJob(ev, kODQuickDraw) ) {
  246.             printing = kODTrue;
  247.             THPrint printRecord = (THPrint)facet->GetCanvas(ev)->GetPlatformPrintJob(ev,kODQuickDraw);
  248.             short device = (**printRecord).prStl.wDev;
  249.             fPrintingPostScript = ((device >> 8) == bDevLaser);
  250.         } else if( facet->GetCanvas(ev)->HasPlatformPrintJob(ev, kODQuickDrawGX) ) {
  251.             printing = kODTrue;
  252.             fPrintingPostScript = kODFalse;
  253.             /*    When GX is installed, QD clipping to regions works in printouts even when
  254.                 printing to a PostScript printer. This means our workaround is not
  255.                 necessary and we can leave the fPrintingPostScript flag false. */
  256.         }
  257.     }
  258.     
  259.     ODCanvas *canvas = facet->GetCanvas(ev);
  260.     
  261.     TempODShape newClip = kODNULL;
  262.     TempODTransform contentTransform = kODNULL;
  263.     
  264.     if( toWindow && !printing ) {
  265.         port = (GrafPtr) facet->GetWindow(ev)->GetPlatformWindow(ev);
  266.         newClip = facet->AcquireWindowAggregateClipShape(ev, canvas);
  267.         if ( toContent ) {
  268.             contentTransform = facet->AcquireWindowContentTransform(ev, canvas);
  269.         } else {
  270.             contentTransform = facet->AcquireWindowFrameTransform(ev, canvas);
  271.         }
  272.     } else {
  273.         port = facet->GetCanvas(ev)->GetQDPort(ev);
  274.         newClip = facet->AcquireAggregateClipShape(ev, canvas);
  275.         if ( toContent ) {
  276.             contentTransform = facet->AcquireContentTransform(ev, canvas);
  277.         } else {
  278.             contentTransform = facet->AcquireFrameTransform(ev, canvas);
  279.         }
  280.     }
  281.     
  282.     ODBoolean xformNotOffset = ! contentTransform->IsQDOffset(ev);
  283.     
  284.     {
  285.         TempODTransform internal = kODNULL;
  286.         if( toContent ) {
  287.             internal = facet->GetFrame(ev)->AcquireInternalTransform(ev,canvas);
  288.             if( internal->GetType(ev) == kODIdentityXform )
  289.                 internal.Release();            // Don't need to worry about it, it's identity
  290.         }
  291.         
  292.         if( internal || clipTo || xformNotOffset ) {
  293.             ODShape *temp = newClip->Copy(ev);        // We will be modifying newClip
  294.             newClip.Release();
  295.             newClip = temp;
  296.         }
  297.         
  298.         if( internal ) {
  299.             // When focusing to content, need to apply inverse of
  300.             // frame's internal transform to clipshape:
  301.             newClip->InverseTransform(ev,internal);
  302.         }
  303.     }
  304.     
  305.     if( clipTo )
  306.         newClip->Intersect(ev,clipTo);
  307.     
  308.     contentTransform->GetOffset(ev, &offset);
  309.     origin = offset.AsQDPoint();
  310.     origin.h = -origin.h;
  311.     origin.v = -origin.v;
  312.     
  313.     if( xformNotOffset ) {
  314.         // Transform newClip by the contentTransform if it involves scale/rotate/etc.
  315.         // But first factor out the final offset since SetOrigin will take care of that later.
  316.         ODTransform *temp = contentTransform->Copy(ev);        // We will be modifying the xform
  317.         contentTransform.Release();
  318.         contentTransform = temp;
  319.         ODPoint move = origin;
  320.         contentTransform->MoveBy(ev, &move);
  321.         newClip->Transform(ev,contentTransform);
  322.     }
  323.         
  324.     fFocusPort = port;
  325.     fPort = ODQDGlobals.thePort;
  326.     if( port != fPort )
  327.         SetPort(port);
  328.  
  329.     fOrigin = topLeft(ODQDGlobals.thePort->portRect);
  330.     if( origin.h != ODQDGlobals.thePort->portRect.left || origin.v != ODQDGlobals.thePort->portRect.top )
  331.         SetOrigin(origin.h,origin.v);
  332.     
  333.     if( fPrintingPostScript ) {
  334.         ODBeginPostScriptClip(ev, newClip);
  335.         fClip = kODNULL;
  336.     } else {
  337.         fClip = ODQDGlobals.thePort->clipRgn;
  338.         ODQDGlobals.thePort->clipRgn = newClip->CopyQDRegion(ev);
  339.     }
  340.     
  341.     return fPrintingPostScript;
  342. }
  343.  
  344.  
  345. //------------------------------------------------------------------------------
  346. // FocusState::EndFocus
  347. //------------------------------------------------------------------------------
  348.  
  349. void
  350. FocusState::EndFocus( )
  351. {
  352.     if( fPort ) {
  353.         if( fFocusPort != ODQDGlobals.thePort )    
  354.             SetPort(fFocusPort);            // In case current port changed since focus
  355.         if( fPrintingPostScript ) {
  356.             ODEndPostScriptClip();
  357.         } else {
  358.             if( fClip ) {
  359.                 DisposeRgn(ODQDGlobals.thePort->clipRgn);
  360.                 ODQDGlobals.thePort->clipRgn = fClip;
  361.             } else {
  362.                 Rect r;
  363.                 SetRect(&r,-32767,-32767,32767,32767);
  364.                 ClipRect(&r);
  365.             }
  366.         }
  367.         if( fOrigin.h!=ODQDGlobals.thePort->portRect.left || fOrigin.v!=ODQDGlobals.thePort->portRect.top )
  368.             SetOrigin(fOrigin.h, fOrigin.v);
  369.         if( ODQDGlobals.thePort!=fPort )
  370.             SetPort(fPort);
  371.         fPort = kODNULL;        // So nothing happens if this is called again
  372.     }
  373. }
  374.  
  375.  
  376. //------------------------------------------------------------------------------
  377. // CFocus
  378. //------------------------------------------------------------------------------
  379.  
  380.  
  381. CFocus::CFocus( Environment *ev, ODFacet *facet )
  382. {
  383.     (void) f.BeginFocus(ev,facet,kODTrue,kODFalse,kODNULL);
  384. }
  385.  
  386.  
  387. CFocus::CFocus( Environment *ev, ODFacet *facet, ODShape *clipTo )
  388. {
  389.     (void) f.BeginFocus(ev,facet,kODTrue,kODFalse,clipTo);
  390. }
  391.  
  392.  
  393. CFocus::~CFocus( )
  394. {
  395.     f.EndFocus();
  396. }
  397.  
  398.  
  399. //------------------------------------------------------------------------------
  400. // CFocusFrame
  401. //------------------------------------------------------------------------------
  402.  
  403.  
  404. CFocusFrame::CFocusFrame( Environment *ev, ODFacet *facet )
  405. {
  406.     (void) f.BeginFocus(ev,facet,kODFalse,kODFalse,kODNULL);
  407. }
  408.  
  409.  
  410. CFocusFrame::CFocusFrame( Environment *ev, ODFacet *facet, ODShape *clipTo )
  411. {
  412.     (void) f.BeginFocus(ev,facet,kODFalse,kODFalse,clipTo);
  413. }
  414.  
  415.  
  416. CFocusFrame::~CFocusFrame( )
  417. {
  418.     f.EndFocus();
  419. }
  420.  
  421.  
  422. //------------------------------------------------------------------------------
  423. // CFocusWindow
  424. //------------------------------------------------------------------------------
  425.  
  426.  
  427. CFocusWindow::CFocusWindow( Environment *ev, ODFacet *facet )
  428. {
  429.     (void) f.BeginFocus(ev,facet,kODTrue,kODTrue,kODNULL);
  430. }
  431.  
  432.  
  433. CFocusWindow::CFocusWindow( Environment *ev, ODFacet *facet, ODShape *clipTo )
  434. {
  435.     (void) f.BeginFocus(ev,facet,kODTrue,kODTrue,clipTo);
  436. }
  437.  
  438.  
  439. CFocusWindow::~CFocusWindow( )
  440. {
  441.     f.EndFocus();
  442. }
  443.  
  444.  
  445. //------------------------------------------------------------------------------
  446. // CFocusWindowFrame
  447. //------------------------------------------------------------------------------
  448.  
  449.  
  450. CFocusWindowFrame::CFocusWindowFrame( Environment *ev, ODFacet *facet )
  451. {
  452.     (void) f.BeginFocus(ev,facet,kODFalse,kODTrue,kODNULL);
  453. }
  454.  
  455.  
  456. CFocusWindowFrame::CFocusWindowFrame( Environment *ev, ODFacet *facet, ODShape *clipTo )
  457. {
  458.     (void) f.BeginFocus(ev,facet,kODFalse,kODTrue,clipTo);
  459. }
  460.  
  461.  
  462. CFocusWindowFrame::~CFocusWindowFrame( )
  463. {
  464.     f.EndFocus();
  465. }
  466.  
  467.  
  468. //------------------------------------------------------------------------------
  469. // BeginFocus  and  EndFocus
  470. //------------------------------------------------------------------------------
  471.  
  472.  
  473. void
  474. BeginFocus( Environment* ev, FocusState* foc, ODFacet* facet,
  475.                  ODBoolean toContent, ODBoolean toWindow, ODShape* clipTo )
  476. {
  477.     foc->BeginFocus(ev,facet,toContent,toWindow,clipTo);
  478. }
  479.  
  480.  
  481. void
  482. EndFocus( FocusState* foc )
  483. {
  484.     foc->EndFocus();
  485. }
  486.